package com.jfl.utils;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
import java.util.stream.IntStream;

import com.jfl.exception.DataParseException;

/**
 * 类转换工具类
 * 
 * @author 赵炎
 * @version [V1.00, 2018年12月4日]
 * @since V1.00
 */
public final class TypeParseUtil
{
    public static final String message = "Could not convert %1$s to %2$s";
    
    public static final String support = "Convert from %1$s to %2$s not currently supported";
    
    private TypeParseUtil()
    {
    }
    
    /**
     * 转换核心实现方法
     *
     * @param value
     * @param type
     *            目标数据类型
     * @param format
     *            输入/输出字符串格式
     * @return Object
     * @throws DataParseException
     */
    public static final Object convert(Object value, String type, String format)
    {
        Locale locale = Locale.getDefault();
        if (value == null)
        {
            return null;
        }
        else if (value.getClass().getName().equalsIgnoreCase(type) || value.getClass().getSimpleName().equalsIgnoreCase(type))
        {
            return value;
        }
        else if ("Object".equalsIgnoreCase(type) || "java.lang.Object".equals(type))
        {
            return value;
        }
        else if (value instanceof String)
        {
            return string2Object(value, type, format, locale);
        }
        else if (value instanceof BigDecimal)
        {
            return decimal2Obj(value, type, locale);
        }
        else if (value instanceof Double)
        {
            return double2Obj(value, type, locale);
        }
        else if (value instanceof Float)
        {
            return float2Obj(value, type, locale);
        }
        else if (value instanceof Long)
        {
            return long2Obj(value, type, locale);
        }
        else if (value instanceof Integer)
        {
            return intr2Obj(value, type, locale);
        }
        else if (value instanceof java.util.Date)
        {
            return date2Obj(value, type, format);
        }
        else if (value instanceof Date)
        {
            return sqlDate2Obj(value, type, format);
        }
        else if (value instanceof Timestamp)
        {
            return time2Obj(value, type, format);
        }
        else if (value instanceof Boolean)
        {
            return bool2Obj(value, type);
        }
        else if ("String".equalsIgnoreCase(type))
        {
            return value.toString();
        }
        else
        {
            throw new DataParseException(String.format(support, value.getClass().getName(), type));
        }
    }
    
    /** 
     * 布尔类型
     * @param value
     * @param type
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object bool2Obj(Object value, String type)
    {
        String fromType = "Boolean";
        Boolean bol = (Boolean)value;
        if ("Boolean".equalsIgnoreCase(type))
        {
            return bol;
        }
        else if ("String".equalsIgnoreCase(type))
        {
            return bol.toString();
        }
        else if ("Integer".equalsIgnoreCase(type))
        {
            if (bol)
            {
                return new Integer(1);
            }
            else
            {
                return new Integer(0);
            }
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 时间类型
     * @param value
     * @param type
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object time2Obj(Object value, String type, String format)
    {
        String fromType = "Timestamp";
        Timestamp tme = (Timestamp)value;
        if ("String".equalsIgnoreCase(type))
        {
            if (format == null || format.length() == 0)
            {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tme).toString();
            }
            else
            {
                SimpleDateFormat sdf = new SimpleDateFormat(format);
                return sdf.format(new java.util.Date(tme.getTime()));
            }
        }
        else if ("Date".equalsIgnoreCase(type))
        {
            return new java.util.Date(tme.getTime());
        }
        else if ("java.sql.Date".equalsIgnoreCase(type))
        {
            return new Date(tme.getTime());
        }
        else if ("Time".equalsIgnoreCase(type))
        {
            return new Time(tme.getTime());
        }
        else if ("Timestamp".equalsIgnoreCase(type))
        {
            return value;
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 日期类型
     * @param value
     * @param type
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object sqlDate2Obj(Object value, String type, String format)
    {
        String fromType = "Date";
        Date dte = (Date)value;
        if ("String".equalsIgnoreCase(type))
        {
            if (format == null || format.length() == 0)
            {
                return dte.toString();
            }
            else
            {
                SimpleDateFormat sdf = new SimpleDateFormat(format);
                return sdf.format(new java.util.Date(dte.getTime()));
            }
        }
        else if ("Date".equalsIgnoreCase(type))
        {
            return new java.util.Date(dte.getTime());
        }
        else if ("java.sql.Date".equalsIgnoreCase(type))
        {
            return value;
        }
        else if ("Time".equalsIgnoreCase(type))
        {
            throw new DataParseException("Conversion from " + fromType + " to " + type + " not currently supported");
        }
        else if ("Timestamp".equalsIgnoreCase(type))
        {
            return new Timestamp(dte.getTime());
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 时间类型
     * @param value
     * @param type
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object date2Obj(Object value, String type, String format)
    {
        String fromType = "Date";
        java.util.Date dte = (java.util.Date)value;
        if ("String".equalsIgnoreCase(type))
        {
            if (format == null || format.length() == 0)
            {
                return dte.toString();
            }
            else
            {
                SimpleDateFormat sdf = new SimpleDateFormat(format);
                return sdf.format(dte);
            }
        }
        else if ("Date".equalsIgnoreCase(type))
        {
            return value;
        }
        else if ("java.sql.Date".equalsIgnoreCase(type))
        {
            return new Date(dte.getTime());
        }
        else if ("Time".equalsIgnoreCase(type))
        {
            return new Time(dte.getTime());
        }
        else if ("Timestamp".equalsIgnoreCase(type))
        {
            return new Timestamp(dte.getTime());
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 整型
     * @param value
     * @param type
     * @param locale
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object intr2Obj(Object value, String type, Locale locale)
    {
        String fromType = "Integer";
        Integer intgr = (Integer)value;
        if ("String".equalsIgnoreCase(type))
        {
            return getNf(locale).format(intgr.toString());
        }
        else if ("Double".equalsIgnoreCase(type))
        {
            return new Double(intgr.toString());
        }
        else if ("Float".equalsIgnoreCase(type))
        {
            return new Float(intgr.toString());
        }
        else if ("BigDecimal".equalsIgnoreCase(type))
        {
            String str = intgr.toString();
            BigDecimal retBig = new BigDecimal(intgr.toString());
            int iscale = str.indexOf(".");
            int keylen = str.length();
            if (iscale > -1)
            {
                iscale = keylen - (iscale + 1);
                return retBig.setScale(iscale, 5);
            }
            else
            {
                return retBig.setScale(0, 5);
            }
        }
        else if ("Long".equalsIgnoreCase(type))
        {
            return new Long(intgr.toString());
        }
        else if ("Integer".equalsIgnoreCase(type))
        {
            return value;
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 长整型
     * @param value
     * @param type
     * @param locale
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object long2Obj(Object value, String type, Locale locale)
    {
        String fromType = "Long";
        Long lng = (Long)value;
        if ("String".equalsIgnoreCase(type))
        {
            return getNf(locale).format(lng.toString());
        }
        else if ("Double".equalsIgnoreCase(type))
        {
            return new Double(lng.toString());
        }
        else if ("Float".equalsIgnoreCase(type))
        {
            return new Float(lng.toString());
        }
        else if ("BigDecimal".equalsIgnoreCase(type))
        {
            return new BigDecimal(lng.toString());
        }
        else if ("Long".equalsIgnoreCase(type))
        {
            return value;
        }
        else if ("Integer".equalsIgnoreCase(type))
        {
            return new Integer(lng.toString());
        }
        else if ("Date".equalsIgnoreCase(type))
        {
            return new java.util.Date(lng);
        }
        else if ("java.sql.Date".equalsIgnoreCase(type))
        {
            return new Date(lng);
        }
        else if ("Time".equalsIgnoreCase(type))
        {
            return new Time(lng);
        }
        else if ("Timestamp".equalsIgnoreCase(type))
        {
            return new Timestamp(lng);
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 浮点型
     * @param value
     * @param type
     * @param locale
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object float2Obj(Object value, String type, Locale locale)
    {
        String fromType = "Float";
        Float flt = (Float)value;
        if ("String".equalsIgnoreCase(type))
        {
            return getNf(locale).format(flt.toString());
        }
        else if ("BigDecimal".equalsIgnoreCase(type))
        {
            return new BigDecimal(flt.toString());
        }
        else if ("Double".equalsIgnoreCase(type))
        {
            return new Double(flt.toString());
        }
        else if ("Float".equalsIgnoreCase(type))
        {
            return value;
        }
        else if ("Long".equalsIgnoreCase(type))
        {
            return new Long(flt.toString());
        }
        else if ("Integer".equalsIgnoreCase(type))
        {
            return new Integer(flt.toString());
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 双精度浮点型
     * @param value
     * @param type
     * @param locale
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object double2Obj(Object value, String type, Locale locale)
    {
        String fromType = "Double";
        Double dbl = (Double)value;
        if ("String".equalsIgnoreCase(type))
        {
            return getNf(locale).format(dbl.toString());
        }
        else if ("Double".equalsIgnoreCase(type))
        {
            return value;
        }
        else if ("Float".equalsIgnoreCase(type))
        {
            return new Float(dbl.toString());
        }
        else if ("Long".equalsIgnoreCase(type))
        {
            return new Long(dbl.toString());
        }
        else if ("Integer".equalsIgnoreCase(type))
        {
            return new Integer(dbl.toString());
        }
        else if ("BigDecimal".equalsIgnoreCase(type))
        {
            return new BigDecimal(dbl.toString());
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 数字型
     * @param value
     * @param type
     * @param locale
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object decimal2Obj(Object value, String type, Locale locale)
    {
        String fromType = "BigDecimal";
        BigDecimal bigD = (BigDecimal)value;
        if ("String".equalsIgnoreCase(type))
        {
            return getNf(locale).format(bigD.toString());
        }
        else if ("BigDecimal".equalsIgnoreCase(type))
        {
            return value;
        }
        else if ("Double".equalsIgnoreCase(type))
        {
            return new Double(bigD.toString());
        }
        else if ("Float".equalsIgnoreCase(type))
        {
            return new Float(bigD.toString());
        }
        else if ("Long".equalsIgnoreCase(type))
        {
            return new Long(bigD.toString());
        }
        else if ("Integer".equals(type))
        {
            return new Integer(bigD.toString());
        }
        else
        {
            throw new DataParseException(String.format(support, fromType, type));
        }
    }
    
    /** 
     * 字符型
     * @param value
     * @param type
     * @param format
     * @param locale
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object string2Object(Object value, String type, String format, Locale locale)
    {
        String fromType = "String";
        String str = (String)value;
        try
        {
            if ("String".equalsIgnoreCase(type))
            {
                return value;
            }
            else if (str.length() == 0)
            {
                return null;
            }
            else if ("Boolean".equalsIgnoreCase(type))
            {
                if (str.equalsIgnoreCase("TRUE"))
                {
                    return new Boolean(true);
                }
                else
                {
                    return new Boolean(false);
                }
            }
            else if ("Double".equalsIgnoreCase(type))
            {
                Number tempNum = getNf(locale).parse(str.replaceAll(",", ""));
                return new Double(tempNum.toString());
            }
            else if ("BigDecimal".equalsIgnoreCase(type))
            {
                BigDecimal retBig = new BigDecimal(str.replaceAll(",", ""));
                int iscale = str.indexOf(".");
                int keylen = str.length();
                if (iscale > -1)
                {
                    iscale = keylen - (iscale + 1);
                    return retBig.setScale(iscale, 5);
                }
                else
                {
                    return retBig.setScale(0, 5);
                }
            }
            else if ("Float".equalsIgnoreCase(type))
            {
                Number tempNum = getNf(locale).parse(str.replaceAll(",", ""));
                return new Float(tempNum.toString());
                
            }
            else if ("Long".equalsIgnoreCase(type))
            {
                NumberFormat nf = getNf(locale);
                nf.setMaximumFractionDigits(0);
                Number tempNum = nf.parse(str.replaceAll(",", ""));
                return new Long(tempNum.toString());
            }
            else if ("Integer".equalsIgnoreCase(type))
            {
                NumberFormat nf = getNf(locale);
                nf.setMaximumFractionDigits(0);
                Number tempNum = nf.parse(str.replaceAll(",", ""));
                return new Integer(tempNum.toString());
            }
            else if ("Date".equalsIgnoreCase(type))
            {
                if (format == null || format.length() == 0)
                {
                    String separator = String.valueOf(str.charAt(4));
                    StringBuilder pattern;
                    if (separator.matches("\\d*"))
                    {
                        pattern = new StringBuilder("yyyyMMdd HH:mm:ss");
                        format = pattern.substring(0, str.length());
                    }
                    else
                    {
                        pattern = new StringBuilder("yyyy").append(separator).append("MM").append(separator).append("dd HH:mm:ss");
                        format = pattern.substring(0, str.length());
                    }
                }
                SimpleDateFormat sdf = new SimpleDateFormat(format);
                return sdf.parse(str);
            }
            else if ("java.sql.Date".equalsIgnoreCase(type))
            {
                if (format == null || format.length() == 0)
                {
                    try
                    {
                        return Date.valueOf(str);
                    }
                    catch (Exception e)
                    {
                        try
                        {
                            DateFormat df = null;
                            if (locale != null)
                            {
                                df = DateFormat.getDateInstance(3, locale);
                            }
                            else
                            {
                                df = DateFormat.getDateInstance(3);
                            }
                            java.util.Date fieldDate = df.parse(str);
                            return new Date(fieldDate.getTime());
                        }
                        catch (ParseException e1)
                        {
                            throw new DataParseException(String.format(message, str, type), e);
                        }
                    }
                }
                SimpleDateFormat sdf = new SimpleDateFormat(format);
                java.util.Date fieldDate = sdf.parse(str);
                return new Date(fieldDate.getTime());
            }
            else if ("Timestamp".equalsIgnoreCase(type))
            {
                if (str.length() == 10)
                {
                    str = str + " 00:00:00";
                }
                if (format == null || format.length() == 0)
                {
                    try
                    {
                        return Timestamp.valueOf(str);
                    }
                    catch (Exception e)
                    {
                        try
                        {
                            DateFormat df = null;
                            if (locale != null)
                            {
                                df = DateFormat.getDateTimeInstance(3, 3, locale);
                            }
                            else
                            {
                                df = DateFormat.getDateTimeInstance(3, 3);
                            }
                            java.util.Date fieldDate = df.parse(str);
                            return new Timestamp(fieldDate.getTime());
                        }
                        catch (ParseException e1)
                        {
                            throw new DataParseException(String.format(message, str, type), e);
                        }
                    }
                }
                try
                {
                    SimpleDateFormat sdf = new SimpleDateFormat(format);
                    java.util.Date fieldDate = sdf.parse(str);
                    return new Timestamp(fieldDate.getTime());
                }
                catch (ParseException e)
                {
                    throw new DataParseException(String.format(message, str, type), e);
                }
            }
            else
            {
                throw new DataParseException(String.format(support, fromType, type));
            }
        }
        catch (Exception e)
        {
            throw new DataParseException(String.format(message, str, type), e);
        }
    }
    
    /** 
     * <一句话功能简述>
     * @param locale
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static NumberFormat getNf(Locale locale)
    {
        NumberFormat nf = null;
        if (locale == null)
        {
            nf = NumberFormat.getNumberInstance();
        }
        else
        {
            nf = NumberFormat.getNumberInstance(locale);
        }
        nf.setGroupingUsed(false);
        return nf;
    }
    
    /** 
     * 转换为布尔值
     * @param obj
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final Boolean convertToBoolean(Object obj)
    {
        return (Boolean)convert(obj, "Boolean", null);
    }
    
    /** 
     * 转换为整型
     * @param obj
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final Integer convertToInteger(Object obj)
    {
        return (Integer)convert(obj, "Integer", null);
    }
    
    /** 转换为字符串 */
    public static final String convertToString(Object obj)
    {
        return (String)convert(obj, "String", null);
    }
    
    /** 
     * 转换为字符串
     * @param obj
     * @param defaultValue
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final String convertToString(Object obj, String defaultValue)
    {
        Object s = convert(obj, "String", null);
        if (s != null)
        {
            return (String)s;
        }
        else
        {
            return "";
        }
    }
    
    /** 
     * 转换为长整型 
     * @param obj
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final Long convertToLong(Object obj)
    {
        return (Long)convert(obj, "Long", null);
    }
    
    /** 
     * 转换为双精度型
     * @param obj
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final Double convertToDouble(Object obj)
    {
        return (Double)convert(obj, "Double", null);
    }
    
    /** 
     * 转换为浮点型 
     * @param obj
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final Double convertToFloat(Object obj)
    {
        return (Double)convert(obj, "Float", null);
    }
    
    /** 
     * 转换为数值型
     * @param obj
     * @param scale
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final BigDecimal convertToBigDecimal(Object obj, int scale)
    {
        return ((BigDecimal)convert(obj, "BigDecimal", null)).setScale(scale, 5);
    }
    
    /** 
     * 转换为日期型
     * @param obj
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final java.util.Date convertToDate(Object obj, String format)
    {
        return (java.util.Date)convert(obj, "Date", format);
    }
    
    /** 
     * 转换为日期型
     * @param obj
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final Date convertToSqlDate(Object obj, String format)
    {
        return (Date)convert(obj, "java.sql.Date", format);
    }
    
    /** 
     * 转换为日期型
     * @param obj
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final Timestamp convertToTimestamp(Object obj, String format)
    {
        return (Timestamp)convert(obj, "Timestamp", format);
    }
    
    public static String[] convertToStringArray(Object object)
    {
        if (object instanceof List)
        {
            @SuppressWarnings("rawtypes")
            List list = (List)object;
            String[] ss = new String[list.size()];
            IntStream.range(0, list.size()).forEach(i -> {
                ss[i] = FastJsonUtil.toJSONString(list.get(i));
            });
            return ss;
        }
        return new String[] {FastJsonUtil.toJSONString(object)};
    }
    
}
